package com.zxmr.utility.action;

import java.util.List;

import com.alibaba.fastjson.JSON;
import com.zxmr.action.Request;
import com.zxmr.action.Response;
import com.zxmr.action.ResponsePayload;
import com.zxmr.action.ResultCode;
import com.zxmr.domain.Notification;
import com.zxmr.domain.Task;
import com.zxmr.domain.TaskPriority;
import com.zxmr.domain.TaskState;
import com.zxmr.domain.account.User;
import com.zxmr.domain.activity.Activity;
import com.zxmr.domain.activity.ActivityEntity;
import com.zxmr.domain.service.ActivityService;
import com.zxmr.domain.service.NotificationService;
import com.zxmr.domain.service.TaskSearchBean;
import com.zxmr.domain.service.TaskService;
import com.zxmr.navigate.ExecuteException;
import com.zxmr.navigate.Executor;
import com.zxmr.util.ResourceManager;
import com.zxmr.util.Utils;
import com.zxmr.utility.dto.JSONListDTO;
import com.zxmr.utility.service.UserActionTraceService;

public class TaskAction extends Executor{

	enum method{
		add,
		applyApprove,
		approve,
		reject,
		query,
		activity,
	}
	@Override
	public void execute(Request request, Response response) {
		
		try
		{
			method m = Enum.valueOf(method.class, this.getElement().getMethod());
			switch(m)
			{
			case add:
				add(request,response);
				break;
			case applyApprove:
				applyApprove(request,response);
				break;
			case approve:
				approve(request,response);
				break;
			case reject:
				reject(request,response);
				break;
			case query:
				query(request,response);
				break;
			case activity:
				activity(request,response);
				break;
			}

		}catch(Exception e)
		{
			ResponsePayload payload = new ResponsePayload();
			if(e instanceof ExecuteException)
			{
				payload.setValue(e.getMessage());
			}else
			{
				e.printStackTrace();
				payload.setValue("internal error");
			}
			response.setPayload(payload);
			response.setResult(ResultCode.COMPONENT_ERROR);
		}
	}
	
	private void add(Request request, Response response)throws ExecuteException
	{
		Task task = parseAdd(request);
		validateAddParameter(task);
		
		task.setAssigner(request.getAccount().getName());
		task.setCreateDate(Utils.getCurrentTime());
		task.setState(TaskState.processing);
		task.setCompany(request.getAccount().getCompany());
		
		TaskService service = new TaskService();
		if(!service.add(task))
			this.internalErrorResponse(response);
		else
		{
			// send notification to assignee
			taskAddNotification(task);
			// add user action trace
			UserActionTraceService userTraceService = new UserActionTraceService();
			String action  = ResourceManager.getInstance().getMessage("com.zxmr.utility.addTask", String.valueOf(task.getId()),task.getTitle());
			userTraceService.addActionTrace(request.getAccount(), action);
		}
	}
	private void taskAddNotification(Task task)
	{
		Notification notification = new Notification();
		notification.setTime(Utils.getCurrentTime());
		notification.setUser(task.getAssignee());
		notification.setType("task");
		notification.setContent(ResourceManager.getInstance().getMessage("com.zxmr.utility.noti.addTask", task.getAssigner(),task.getTitle()));
		
		NotificationService service = new NotificationService();
		service.add(notification);
	}
	private Task parseAdd(Request request)throws ExecuteException
	{
		try
		{
			return JSON.parseObject(request.getRequestParameters().get("parameters"), Task.class);
		}catch(Exception e)
		{
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
		}
	}
	private void validateAddParameter(Task task)throws ExecuteException
	{
		if(task == null)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
		
		if(Utils.isStringEmptyWithTrim(task.getTitle()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.task.notitle"));
		
		if(Utils.isStringEmptyWithTrim(task.getAssignee()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.task.noassignee"));
		
		if(Utils.isStringEmptyWithTrim(task.getEndDate()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.task.notime"));
		
		if(task.getPriority() == null)
			task.setPriority(TaskPriority.normal);
	}
	private void approve(Request request, Response response)throws ExecuteException
	{
		long id = getID(request);
		String responseContent = request.getRequestParameters().get("response");
		TaskService service = new TaskService();
		Task task = service.query(id);
		
		authCompany(request,task);
		isAssigner(task,request.getAccount());
		
		if(task.getState() != TaskState.approving)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.task.wrongState"));
		
		service.approve(task, responseContent);
	}
	private void reject(Request request, Response response)throws ExecuteException
	{
		long id = getID(request);
		String responseContent = request.getRequestParameters().get("response");
		TaskService service = new TaskService();
		Task task = service.query(id);
		
		authCompany(request,task);
		isAssigner(task,request.getAccount());
		
		if(task.getState() != TaskState.approving)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.task.wrongState"));
		service.reject(task, responseContent);
		
	}
	private void applyApprove(Request request, Response response)throws ExecuteException
	{
		long id = getID(request);
		String responseContent = request.getRequestParameters().get("response");
		
		TaskService service = new TaskService();
		Task task = service.query(id);
		
		authCompany(request,task);
		isAssignee(task,request.getAccount());

		if(task.getState() != TaskState.processing && task.getState() != TaskState.reject)
		{
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.task.notProcessingState"));
		}
		if(Utils.getCurrentTime().compareTo(task.getEndDate()) > 0)
		{
			task.setState(TaskState.expired);		
			service.expired(task);
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.task.expired"));
		}else
		{
			service.applyApprove(task, responseContent);
		}
		
	}
	private void authCompany(Request request,Task task)throws ExecuteException
	{
		if(task == null || task.getCompany() != request.getAccount().getCompany())
		{
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.noauth"));
		}
	}
	private void isAssignee(Task task,User user)throws ExecuteException
	{
		if(!task.getAssignee().equals(user.getName()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.noauth"));
	}
	private void isAssigner(Task task,User user)throws ExecuteException
	{
		if(!task.getAssigner().equals(user.getName()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.noauth"));
	}
	private long getID(Request request)throws ExecuteException
	{
		long id = 0;
		try{
			id = Long.parseLong(request.getRequestParameters().get("id"));
		}catch(Exception e)
		{
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
		}
		return id;
	}
	private void query(Request request, Response response)throws ExecuteException
	{
		String parameter = request.getRequestParameters().get("p");
		TaskSearchBean searchBean = null;
		try
		{
			searchBean = JSON.parseObject(parameter, TaskSearchBean.class);
		}catch(Exception e)
		{
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
		}
		
		TaskService service = new TaskService();
		List<Task> tasks = service.queryContractPagination(searchBean);
		int count = service.queryContractPaginationCount(searchBean);
		
		JSONListDTO dto = new JSONListDTO();
		dto.setRows(tasks);
		dto.setTotal(count);
		
		ResponsePayload payload = new ResponsePayload(JSON.toJSONString(dto));
		response.setPayload(payload);
		
	}
	private void activity(Request request, Response response)throws ExecuteException
	{
		long id = getID(request);
		
		TaskService service = new TaskService();
		Task task = service.query(id);
		
		authCompany(request,task);
		if(!task.getAssignee().equals(request.getAccount().getName()) && !task.getAssigner().equals(request.getAccount().getName()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.noauth"));
		
		ActivityService activityService = new ActivityService();
		List<Activity> activity = activityService.queryAllActivity(ActivityEntity.task, task.getId());
		
		ResponsePayload payload = new ResponsePayload(JSON.toJSONString(activity));
		response.setPayload(payload);
	}
}
